/*************************************************************
* Strip Packing Problem
* 
*
* */
#ifndef CONTENEDOR_H
#define CONTENEDOR_H

#include<iostream>
#include<fstream>
#include<string>
#include "rectangulo.h"
#include <list>
#include <stack>
#include <limits.h>
#include <stdlib.h>


using namespace std;


/** Clase Contenedor
 * Clase que representa la cinta (strip) donde se pondrán
 * los rectángulos. Contiene los métodos necesarios
 * para buscar la solución
 * */
class Contenedor {
   public:
      /* Estructura tramo para poder definir el contorno
       * i = inicio tramo. f = fin tramo. h = altura tramo
       * */
       struct tramo {
         int i;
         int f;
         int h;
      };
      
  private:
     
      //Rectangulo * R;
      int W; //Ancho del contenedor
      int H; //Altura actual de contenedor
      
      
      /* MIRIAM: dejo lo de la pila por si acaso aquí comentadita xDDD.
      stack<Rectangulo> solucion; //Pila con los rectángulos de la solución. Array? Lista?
      
      PD: La lista de candidatos no se toca, ya que para mi constructor se tiene que dejar así, 
      o si no avisen xDDD
      */
      list<Rectangulo> solucion; //Pila "encubierta de lista" con los rectángulos de la solución.
      list <Rectangulo> imaginario; //Lista de huecos que no se han podido llenar.
      list <Rectangulo> candidatos; //Lista de candidatos
      /** Definiremos el contorno como una lista de tramos
       * */
      list<tramo> contorno;      
      
      
      /** Devuelve el alto maximo del contorno entre in y fin
       * @param ini inicio del bloque
       * @param fin fin del bloque
       * @return altura maxima
       * */
      int maxBottom(int ini, int fin);

       /** Devuelve el "left" maximo del contorno entre in y fin
       * @param ini inicio del bloque
       * @param fin fin del bloque
       * @return altura maxima
       * */
      int maxLeft(int h, int ini);
      
      /** Coloca el rectangulo siguiendo el orden bottomLeft
      * @param rect rectangulo a colocar
      * */
      void bottomLeft(Rectangulo rect, int &pos, int &h);
   
      /** Actualizar el contorno, de los rectángulos añadidos */      
      void setContorno(int i, int f, int h);
      int cabe(Rectangulo r);
      
      
      /** Crea un rectángulo imaginario si en el hueco no cabe ningún rectángulo posible*/
      int rellenarVacios(list <Rectangulo> l);
      
	public: 
   
         void listarContorno();

		/** Constructor por defecto */
		Contenedor();

		/** Constructor con parametros */
		Contenedor( int w); 

		/** Obtener ancho */
		int getW();

		/** Obtener alto */
		int getH();

      void Test (list <Rectangulo> l);
		/** Devuelve la última posición del contenedor, por lo general W-1
		* @return última posicion del contenedor
		* */
		int getUltimaPos();
		
		 tramo getHuecoMinimo();

		/**
		* Añade un rectangulo haciendo el bottomleft
		* @param r Rectangulo a introducir
		* */
		void addRectangulo(Rectangulo r);

		/**
		* Añade un Rectangulo en la posición y altura especificadas sin hacer bottom left
		* @param r Rectangulo a introducir
		* @param pos_inicio posicion (contada desde 0)dónde introducir el Rectangulo
		* @param h_inicio altura a la que colocar el Rectangulo, debería ser la altura del tramo donde se situará
		* */
		void addRectangulo(Rectangulo r, int pos_inicio, int h_inicio);
      
      /** TODO ! IMPORTANTE: metodo que calcule la altura del rectangulo
       * Tiene que hacer: coger la lista solucion e ir metiendo uno por uno los
       * rectangulos con addRectangulo(r).
       * Tiene que devolver la altura final del rectangulo
       * Es simplemente un bucle pero hay que tener en cuenta los posible huecos vacios
       * y tendría que llamar a Rellenar dentro de un bucle cada vez q introduce un rectangulo.
       * Rellenar tiene que pasar tantas veces como huecos vacios inservibles queden, que se podría hacer desde esta función
       * o desde dentro de Rellenar, por si hay más de un hueco que no sirva.
       * 
       * */

      /**
      * Actualiza la H si es mayor que la actual
      * */
      void setH(int h_);
      
      int calcularAltura(list<Rectangulo> sol_in);
      void reiniciarContenedor();
      int calcularArea(list<Rectangulo> lista);
      int calcularAreaVacia(list <Rectangulo> lista, int h);
      
		/** Destructor */
		~Contenedor() {} //{cout << "CONTENEDOR::Destructor" << endl; }
   };

#endif
